package apiimpl

import (
	"context"
	"errors"
	"fmt"
	"go-caipu/pkg/services/dto"
	"go-caipu/pkg/util"
	"gorm.io/gorm/clause"
	"time"

	"gorm.io/gorm"

	"go-caipu/pkg/infra/log"
	"go-caipu/pkg/services/admin/model"
	"go-caipu/pkg/services/admin/sysapi"
)

type store interface {
	GetSysApiPage(ctx context.Context, cmd sysapi.GetSysApiPageCommand) (data []sysapi.SysApi, num int64, err error)
	GetSysApi(ctx context.Context, category []string) (data []sysapi.SysApi, err error)
	Get(ctx context.Context, cmd sysapi.GetSysApiCommand) (sysapi.SysApi, error)
	Insert(ctx context.Context, post sysapi.SysApi) error
	//BatchInsert 批量插入
	BatchInsert(ctx context.Context, cmd []sysapi.ApiCategory) (err error)
	Update(ctx context.Context, post sysapi.SysApi) error
	Remove(ctx context.Context, cmd sysapi.RemoveSysApiCommand) error

	GetSysApiCategoryList(ctx context.Context, cmd sysapi.GetApiCategoriesCommand) (result []sysapi.ApiCategory, err error)
	InsertApiCategory(ctx context.Context, post sysapi.ApiCategory) error
	UpdateApiCategory(ctx context.Context, post sysapi.ApiCategory) error
	RemoveApiCategory(ctx context.Context, cmd sysapi.ApiCategory) error
}
type sqlStore struct {
	db     *gorm.DB
	logger log.Logger
}

func ProvideStore(db *gorm.DB) sqlStore {
	return sqlStore{
		db:     db,
		logger: log.New("dept.store"),
	}
}
func (s sqlStore) GetSysApiPage(ctx context.Context, cmd sysapi.GetSysApiPageCommand) (result []sysapi.SysApi, num int64, err error) {
	var items []model.SysApi
	err = s.db.Model(&model.SysApi{}).Scopes(
		dto.MakeCondition(cmd.GetNeedSearch()),
		func(db *gorm.DB) *gorm.DB {
			if cmd.Category != "" {
				ids := s.getChildrenCategoryIds(ctx, cmd.Category)
				ids = append(ids, cmd.Category)
				return db.Where("category in ?", ids)
			}
			return db
		},
		dto.Paginate(cmd.GetPageSize(), cmd.GetPageIndex()),
	).Preload("CategoryDto").Preload("CreateUser").Preload("UpdateUser").Find(&items).Limit(-1).Offset(-1).Count(&num).Error
	if err != nil {
		return
	}
	for _, v := range items {
		result = append(result, ConvertToDTO(v))
	}
	return
}

func (s sqlStore) GetSysApi(ctx context.Context, categoryId []string) (data []sysapi.SysApi, err error) {
	err = s.db.Model(&model.SysApi{}).Scopes(func(db *gorm.DB) *gorm.DB {
		if len(categoryId) != 0 {
			return db.Where("category IN ?", categoryId)
		}
		return db
	}).Find(&data).Error
	return
}

// 递归查询子级分类编号（多次查询数据库）
func (s sqlStore) getChildrenCategoryIds(ctx context.Context, categoryId string) (result []string) {
	var items []model.SysApiCategory
	err := s.db.Model(&model.SysApiCategory{}).Where("parent_id = ?", categoryId).Find(&items).Error
	if err != nil {
		return
	}
	for _, v := range items {

		result = append(result, util.Int64ToString(v.ID))
		result = append(result, s.getChildrenCategoryIds(ctx, util.Int64ToString(v.ID))...)
	}
	return
}

func ConvertToDTO(model model.SysApi) sysapi.SysApi {
	result := sysapi.SysApi{
		Id:        model.Id,
		Category:  model.Category,
		Handle:    model.Handle,
		Title:     model.Title,
		Path:      model.Path,
		Type:      model.Type,
		Action:    model.Action,
		Remark:    model.Remark,
		ControlBy: model.ControlBy,
	}
	if model.CategoryDto != nil {
		result.CategoryName = model.CategoryDto.Name
	}
	result.CreatedAt = model.CreatedAt.Format("2006-01-02 15:04:05")
	result.UpdatedAt = model.UpdatedAt.Format("2006-01-02 15:04:05")
	result.CreateUserString = model.CreateUser.NickName
	result.UpdateUserString = model.UpdateUser.NickName
	return result
}
func (s sqlStore) Get(ctx context.Context, cmd sysapi.GetSysApiCommand) (result sysapi.SysApi, err error) {
	var data model.SysApi
	err = s.db.Model(&data).First(&data, cmd.Id).Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New(fmt.Sprintf("FileKey=%d record Not found", cmd.Id))
		return
	}
	if err != nil {
		s.logger.Log(fmt.Sprintf("get  sysapi=%d  error:%s", cmd.Id, err.Error()))
		return
	}
	return ConvertToDTO(data), nil
}

func ConvertToDT(model sysapi.SysApi, cmd *model.SysApi) {
	cmd.Id = model.Id
	cmd.Category = model.Category
	cmd.Handle = model.Handle
	cmd.Title = model.Title
	cmd.Path = model.Path
	cmd.Type = model.Type
	cmd.Action = model.Action
	cmd.Remark = model.Remark
}
func (s sqlStore) Insert(ctx context.Context, cmd sysapi.SysApi) (err error) {
	tx := s.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var data model.SysApi
	ConvertToDT(cmd, &data)
	data.CreatedAt = time.Now()
	data.CreateBy = cmd.CreateBy

	err = tx.Create(&data).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("insert  sysapi  error:%s", err.Error()))
		return err
	}
	return nil
}

// BatchInsert 批量插入
func (s sqlStore) BatchInsert(ctx context.Context, cmd []sysapi.ApiCategory) (err error) {
	tx := s.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	categorys := make([]model.SysApiCategory, 0)
	apis := make([]model.SysApi, 0)
	for i := range cmd {
		//插入category
		category := model.SysApiCategory{
			ID:       cmd[i].ID,
			Name:     cmd[i].Title,
			ParentID: cmd[i].ParentID,
		}
		category.CreateBy = cmd[i].OperUser
		category.UpdateBy = cmd[i].OperUser
		category.CreatedAt = time.Now()
		category.UpdatedAt = time.Now()
		categorys = append(categorys, category)
		//插入api
		for _, item := range cmd[i].SysApis {
			api := model.SysApi{
				Category: cmd[i].ID,
				Id:       item.Id,
				Handle:   item.Handle,
				Title:    item.Title,
				Path:     item.Path,
				Type:     item.Type,
				Action:   item.Action,
				Remark:   item.Remark,
			}
			api.CreateBy = cmd[i].OperUser
			api.UpdateBy = cmd[i].OperUser
			api.CreatedAt = time.Now()
			api.UpdatedAt = time.Now()
			apis = append(apis, api)
		}
	}
	err = tx.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "id"}},
		DoUpdates: clause.AssignmentColumns([]string{"name", "parent_id", "created_at", "updated_at", "update_by", "create_by"}),
	}).Create(&categorys).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("batch insert sysapi_category  error:%s", err.Error()))
		return err
	}
	err = tx.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "id"}},
		DoUpdates: clause.AssignmentColumns([]string{"handle", "title", "path", "type", "action", "remark", "created_at", "updated_at", "update_by", "create_by"}),
	}).Create(&apis).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("export  sysapi  error:%s", err.Error()))
		return err
	}
	return nil
}

func (s sqlStore) Update(ctx context.Context, cmd sysapi.SysApi) (err error) {
	tx := s.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	//查询当前部门名称是否存在
	var data model.SysApi
	err = s.db.Model(&data).First(&data, cmd.Id).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("check SysApi id=%d is exists error:%s", cmd.Id, err.Error()))
		return err
	}
	ConvertToDT(cmd, &data)
	data.UpdatedAt = time.Now()
	data.UpdateBy = cmd.UpdateBy
	err = tx.Save(&data).Error
	if err != nil {
		s.logger.Log(fmt.Sprintf("update  sysapi  error:%s", err.Error()))
		return err
	}
	return nil
}

func (s sqlStore) Remove(ctx context.Context, cmd sysapi.RemoveSysApiCommand) (err error) {
	tx := s.db.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var data model.SysApi
	err = tx.Model(&model.SysApi{}).Delete(&data, cmd.Ids).Error
	if err != nil {
		return err
	}
	return
}

func (s sqlStore) GetSysApiCategoryList(ctx context.Context, cmd sysapi.GetApiCategoriesCommand) (result []sysapi.ApiCategory, err error) {
	var items []model.SysApiCategory
	err = s.db.Model(&model.SysApiCategory{}).Scopes(func(db *gorm.DB) *gorm.DB {
		if len(cmd.Ids) != 0 {
			return db.Where("id IN ?", cmd.Ids)
		}
		return db
	}).Find(&items).Error
	if err != nil {
		return
	}
	for _, item := range items {
		result = append(result, sysapi.ApiCategory{
			ID:       item.ID,
			Title:    item.Name,
			ParentID: item.ParentID,
		})
	}
	return
}
func (s sqlStore) InsertApiCategory(ctx context.Context, post sysapi.ApiCategory) error {
	var items model.SysApiCategory
	items.ID = post.ID
	items.Name = post.Title
	items.ParentID = post.ParentID
	items.CreatedAt = time.Now()
	items.UpdatedAt = time.Now()
	items.CreateBy = post.OperUser
	return s.db.Create(&items).Error
}
func (s sqlStore) UpdateApiCategory(ctx context.Context, post sysapi.ApiCategory) error {
	var items model.SysApiCategory
	items.ID = post.ID
	items.Name = post.Title
	items.ParentID = post.ParentID
	items.UpdatedAt = time.Now()
	items.UpdateBy = post.OperUser
	return s.db.Model(&items).Where("id=?", &items.ID).Updates(&items).Error
}
func (s sqlStore) RemoveApiCategory(ctx context.Context, cmd sysapi.ApiCategory) error {
	var data model.SysApiCategory
	data.ID = cmd.ID
	err := s.db.Model(&model.SysApiCategory{}).Delete(&data, cmd.ID).Error
	return err
}
